[结贴]DMA共用缓存区映射到用户进程空间失败,KERNEL

您所在的位置:网站首页 蓝屏data inpage [结贴]DMA共用缓存区映射到用户进程空间失败,KERNEL

[结贴]DMA共用缓存区映射到用户进程空间失败,KERNEL

2023-09-11 04:26| 来源: 网络整理| 查看: 265

小弟试图在驱动程序申请一段公用缓存区连续内存供DMA操作使用,然后在IO响应程序中将这个连续内存的首地址映射给用户程序访问,已降低数据搬移的时间消耗。 在内存开辟(申请)上没有问题,可以满足我的需要,但在映射超过一定大小的公用缓冲区的过程中就会蓝屏。 1.当DMA_SIZE约大于800k时MmMapLockedPagesSpecifyCache会导致蓝屏,当DMA_SIZE在800k以下基本可以正常映射.我也尝试过用 ExAllocatePoolWithTag 和 MmAllocateContiguousMemorySpecifyCache 来申请内存去映射到用户进程空间,也出现这个映射失败的蓝屏情况. 看到看雪中这篇帖子http://bbs.pediy.com/showthread.php?p=818239 中提到映射1M到16M都没有问题,我映射800K以上就蓝屏,不知道代码有没有什么问题,出错函数应该是 MmMapLockedPagesSpecifyCache,但我不清楚问题出在哪里~ 2.目标及调试环境:win7 64bit RAM:4G 开发环境:win7 64bit VS2013 WDK8.1 3.驱动上下文结构体定义(Device.h)   typedef struct _DEVICE_CONTEXT{        struct  _tag_DrvMapApp_Reg{       PHYSICAL_ADDRESS   DevBaseAddr;   //物理地址或者逻辑地址(设备访问需要)       PVOID         DrvBaseAddr;   //内核态虚拟地址(驱动程序访问需要)       PVOID         AppBaseAddr;   //用户态虚拟地址(应用程序访问需要)       unsigned long int   length;       int         isBusy;       PMDL        pMdl;       WDFDMAENABLER    dmaEnable;       WDFCOMMONBUFFER    commonBuffer;       WDFDMATRANSACTION  DmaTransaction;       WDFINTERRUPT    Interrupt;       WDFREQUEST      Request;     }DrvMapAppReg1;     ULONG              Counter_i;          // 资源计数器,记录WDF框架分配给设备的资源个数,counter for WdfCmResourceListGetCount (ResourceListTranslated)     ULONG        OffsetAddressFromApp;    // get offset address that is given by application 偏移地址(由应用程序传递过来)   } DEVICE_CONTEXT, *PDEVICE_CONTEXT; 4.EvtDeviceAdd函数中     #define DMA_SIZE (900*1024)   PVOID            DrvUseAddr1 = NULL;   PHYSICAL_ADDRESS      DevUseAddr1;   WDF_DMA_ENABLER_CONFIG    dmaConfig;    DevUseAddr1.QuadPart  =  0;   WdfDeviceSetAlignmentRequirement(device, FILE_OCTA_ALIGNMENT);  //16字节对齐   //创建一个DMA适配器   WDF_DMA_ENABLER_CONFIG_INIT(  &dmaConfig,                   WdfDmaProfileScatterGather64Duplex,    //通道特性                   DMA_SIZE/20                //单个传输的最大长度,小于65536 (64K)                 );   status = WdfDmaEnablerCreate(  device,                   &dmaConfig,                   WDF_NO_OBJECT_ATTRIBUTES,                   &pDevContext->DrvMapAppReg1.dmaEnable                 );   if (!NT_SUCCESS(status)){     return status;   }  //创建一个DMA传输   status = WdfDmaTransactionCreate(  pDevContext->DrvMapAppReg1.dmaEnable,                     WDF_NO_OBJECT_ATTRIBUTES,                     &pDevContext->DrvMapAppReg1.DmaTransaction                   );   //分配DMA公用缓冲区   status = WdfCommonBufferCreate(    pDevContext->DrvMapAppReg1.dmaEnable,                     DMA_SIZE,                     WDF_NO_OBJECT_ATTRIBUTES,                     &pDevContext->DrvMapAppReg1.commonBuffer                   );   if (status ==  STATUS_SUCCESS){ //能够正常获取     DrvUseAddr1 = WdfCommonBufferGetAlignedVirtualAddress(pDevContext->DrvMapAppReg1.commonBuffer);     DevUseAddr1 = WdfCommonBufferGetAlignedLogicalAddress(pDevContext->DrvMapAppReg1.commonBuffer);     pDevContext->DrvMapAppReg1.DrvBaseAddr = DrvUseAddr1;     pDevContext->DrvMapAppReg1.DevBaseAddr = DevUseAddr1;     pDevContext->DrvMapAppReg1.AppBaseAddr = NULL;     pDevContext->DrvMapAppReg1.isBusy    =  0;     pDevContext->DrvMapAppReg1.length    =  DMA_SIZE;     RtlZeroMemory(pDevContext->DrvMapAppReg1.DrvBaseAddr, pDevContext->DrvMapAppReg1.length);     KdrPrint("DMA_SIZE = %d KB", WdfCommonBufferGetLength(pDevContext->DrvMapAppReg1.commonBuffer) / 1024);   }   else{     return status;   } 5.在EvtIoDeviceControl例程中: 类型定义 typedef struct _tag_DMA_MEMORY{   void * addr; //注意环境切换 win32 or x64  指针变量的长度不一样   unsigned long  length; }DMA_MEMORY_Header, *PDMA_MEMORY_Header;     case PCIeCardDrv_IOCTL_GET_THREAD_ADDR:     //outBuffer返回进程需要使用DMA空间的首地址和长度,在switch之前已经获取       KdrPrint("EvtIoDeviceControl: I am GET_THREAD_ADDR!\n");       MapSharedMemory2App(pDevContext, (PDMA_MEMORY_Header)outBuffer);       WdfRequestCompleteWithInformation(Request, status, OutputBufferLength);       if (!NT_SUCCESS(status)){         goto Exit;       }     break; 6.其中MapSharedMemory2App的具体实现如下: NTSTATUS MapSharedMemory2App(PDEVICE_CONTEXT pDevContext,PDMA_MEMORY_Header pMemoryHeader){  PMDL        pMdl      =  NULL;   PVOID        AppBaseAddr    =  NULL;   pMemoryHeader->addr = NULL;   pMemoryHeader->length = 0;            pMdl = IoAllocateMdl(pDevContext->DrvMapAppReg1.DrvBaseAddr, DMA_SIZE, FALSE, FALSE, NULL);   pMdl->MdlFlags |= MDL_MAPPED_TO_SYSTEM_VA; // 改变MDL的flags为可读状态   MmBuildMdlForNonPagedPool(pMdl); //非页面缓冲池调用这个   AppBaseAddr = MmMapLockedPagesSpecifyCache(pMdl,                  //                         UserMode,                         MmNonCached,                         NULL,                         FALSE,                         NormalPagePriority// | MdlMappingNoWrite                       );  pDevContext->DrvMapAppReg1.AppBaseAddr    =  AppBaseAddr; //保存信息到   pDevContext->DrvMapAppReg1.pMdl        =  pMdl;   pDevContext->DrvMapAppReg1.length      =  DMA_SIZE;   pMemoryHeader->addr              =  AppBaseAddr;   pMemoryHeader->length            =  DMA_SIZE;   KdrPrint("2:pMdl = 0x%x\n", pDevContext->DrvMapAppReg1.pMdl);   KdrPrint("I am MapSharedMemory2App Return\n");   return STATUS_SUCCESS; }希望各位能指点一下原因和怎么解决这个问题,谢谢~

议题征集启动!看雪·第七届安全开发者峰会10月23日上海



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3